// ProjectName: go-learn-demo
// PackageName: oop
// Description: Go语言中，接口实现
// Author: hy.bai
// Date: 2025-07-29 21:53

package interybxb

import (
	"fmt"
)

// 定义一个接口
type Usber interface {
	// 定义一个函数签名(函数签名包括:函数名(参数列表) (返回值列表)),没有函数体。
	// 注意：而且方法不能有接收器
	getName() string
}

// 定义接口的实现：Phone
type Phone struct {
	Name string
}

func (p *Phone) getName() string {
	return p.Name
}

// 定义接口的实现：Computer
type Computer struct {
	Brand string
}

func (c *Computer) getName() string {
	return c.Brand
}

// 测试接口
func TestInter() {
	var phone = &Phone{
		Name: "phone13",
	}
	var computer = &Computer{
		Brand: "MacBook Pro",
	}
	// 注意：此时声明一个接口类型的变量
	// 可以把实现类类型的变量赋值给接口类型的变量
	// 当结构体实现了接口，那么结构体的实例化对象可以赋值给接口(就是一个类型转换)。
	var usber1 Usber = phone
	// 通过接口类型去掉方法，可以动态返回
	fmt.Printf("usber1的类型是%T, %v\n", usber1, usber1.getName()) // usber1的类型是*interybxb.Phone, phone13
	var usber2 Usber = computer
	// 通过接口类型去掉方法，可以动态返回
	fmt.Printf("usber2的类型是%T, %v\n", usber2, usber2.getName()) // usber2的类型是*interybxb.Computer, MacBook Pro
}

// 定义接口的方便之处
// transData函数可以使用所有实现了Usber接口的结构体对象
func transData(usber Usber) string {
	name := usber.getName()
	return fmt.Sprintf("%s处理后的值", name)
}

func TestInterTrans() {
	var phone = &Phone{
		Name: "phone13 Pro",
	}
	var computer = &Computer{
		Brand: "华为电脑",
	}
	// 把实现类类型的变量赋值给接口类型变量
	phoneData := transData(phone)
	fmt.Println(phoneData)
	computerData := transData(computer)
	fmt.Println(computerData)
}

// 空接口断言
func TestUsberAssert() {
	// 注意:inter这个变量必须是空接口类型(interface{})
	var inter interface{} = &Phone{
		Name: "phone13 Pro",
	}
	result, ok := inter.(Usber) // 判断空接口变量指向的值是否Usber类型, 如果是, 则返回true。
	if ok {
		fmt.Println(result.getName())
	}
}
